Index: Lib/pydoc_data/_pydoc.css
===================================================================
--- Lib/pydoc_data/_pydoc.css (revision 87586)
+++ Lib/pydoc_data/_pydoc.css (working copy)
@@ -2,5 +2,233 @@
CSS file for pydoc.
Contents of this file are subject to change without notice.
+*/
+
+/* Setting underline on hover only is less busy. */
+a:link{text-decoration: none;}
+a:visited{text-decoration: none;}
+a:hover, a:active{text-decoration: underline;}
+
+body{
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ font-size: 100%; /* Improves scaling consistency. */
+ color: #000000;
+ background-color: #f8f8f8;
+}
+
+
+/* Contains header, navbar, and content and sets page padding. */
+#page{padding: 1em;}
+
+
+/* Contains title, version, and navigation bar. */
+#page-header{width: 100%;}
+
+
+/* Title */
+#page-title{
+ display: inline-block;
+ margin: 0;
+ padding: 0 2em 0 0;
+ color: #5599cc;
+ background-color: #f8f8f8;
+}
+
+/* Version info */
+#python_version{
+ display: inline-block;
+ margin: 0;
+ padding: 0;
+ font-style: italic;
+ color: #888888;
+ background-color: #f8f8f8;
+}
+
+/* Navigation bar. */
+#navbar{
+ margin: 0;
+ padding: .2em;
+ color: #000000;
+ background-color: #f0f0f4;
+ border: 1px solid #888888;
+ overflow: auto;
+}
+#navbar li{
+ margin: 0;
+ padding: .25em .5em .25em .5em;
+ list-style: none;
+ display: inline-block;
+}
+#navbar form{
+ margin: 0;
+ padding: 0;
+ display: inline-block;
+}
+#navbar a{padding-right: 1em;}
+
+
+/* Contains main content. */
+#page-content{
+ margin-top: 1em;
+ overflow: auto;
+}
+
+/* Content title. */
+#subject{
+ margin: 0;
+ padding: .25em;
+ color: #ffffff;
+ background-color: #5599cc;
+}
+
+
+/* A content section that has a title.
+
+ Combine these with a section type to set the
+ title colors.
+
+ Use:
+
*/
+dl.section dt{
+ font-weight: bold;
+ padding: .75em;
+}
+dl.section dd{
+ padding: 1em;
+ color: #000000;
+ background-color: #f8f8f8;
+}
+
+/* A section with no left vertical bar. */
+dl.subsection dt{
+ font-weight: bold;
+ padding: .25em .25em .25em .5em;
+}
+dl.subsection dd{
+ margin-left: 0;
+ padding: 1ex;
+ color: #000000;
+ background-color: #f8f8f8;
+}
+
+/* Set title colors for section and sub-section. */
+dl.modules{
+ color: #ffffff;
+ background-color: #aa55cc;
+}
+
+dl.module{} /* These are not used yet. */
+
+dl.classes{}
+
+dl.class{}
+
+dl.methods{}
+
+dl.method{}
+
+dl.functions{}
+
+dl.function{}
+
+dl.data{}
+
+ul.data-item li{}
+
+dl.file{
+ color: #ffffff;
+ background-color: #009900;
+}
+
+dl.topics{
+ color: #ffffff;
+ background-color: #5f99cc;
+}
+
+dl.topic{
+ color: #ffffff;
+ background-color: #009900;
+}
+
+dl.error{
+ color: #ffffff;
+ background-color: #cc4444;
+}
+
+
+
+/* index */
+ul.index-lines{padding-left: 9ex;}
+ul.index-lines li{
+ text-indent: -8ex;
+ list-style: none;
+}
+
+
+/* index aligned in columns */
+ul.index-columns{
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ overflow: auto; /* Limit floats. */
+}
+ul.index-columns li{
+ margin: 0 1em .2em 0;
+ width: 15em;
+ float: left;
+}
+
+
+/* links to modules and packages */
+span.module {}
+
+span.package {
+ font-style: italic;
+ color: #555;
+ background-color: #f8f8f8;
+}
+span.package a{
+ font-style: normal;
+ font-weight: bold;
+ font-size: 98%; /* Bold effects floats without this. */
+}
+
+
+pre.docstring{
+ margin: 0;
+ padding: .25em;
+}
+
+
+pre.topic-info{
+ margin: 0;
+ padding: .25em;
+ color: #000000;
+ background-color: #ffffff;
+ border: 1px solid #aaaaaa;
+}
+
+
+pre.python-code{
+ margin: 0;
+ padding: .25em;
+ color: #000000;
+ background-color: #ffffff;
+ border: 1px solid #aaaaaa;
+ overflow: auto;
+}
+pre.python-code code{
+ color: #000000;
+ background-color: #f4f4ff; /* Shows white space. */
+}
+
+
+#page-footer p{
+ color: #888888;
+ background-color: #f8f8f8;
+ text-align: right;
+}
Index: Lib/pydoc.py
===================================================================
--- Lib/pydoc.py (revision 87586)
+++ Lib/pydoc.py (working copy)
@@ -2471,234 +2471,299 @@
def page(self, title, contents):
"""Format an HTML page."""
- css_path = "pydoc_data/_pydoc.css"
- css_link = (
- '' %
- css_path)
- return '''\
-
-Python: %s
-
-%s%s
-''' % (title, css_link, contents)
+ values = dict(title=title,
+ css_path="pydoc_data/_pydoc.css",
+ header=html_header(),
+ content=contents,
+ )
+ template = \
+'''
+
+
+ PyDoc: {title}
+
+
+
+
+
+ {header}
+ {content}
+
+
+
+'''
+ return template.format(**values)
def filelink(self, url, path):
return '%s' % (url, path)
- html = _HTMLDoc()
+ def _index_section(self, title, items, css_class):
+ """Make an index sub-section"""
+ items = '\n
'.join(items)
+ values = dict(title = title,
+ items = items,
+ css_class=css_class,
+ )
+ template = (' {title}'
+ ' '
+ ' '
+ ' '
+ )
+ return template.format(**values)
- def html_navbar():
- version = "%s [%s, %s]" % (platform.python_version(),
- platform.python_build()[0],
- platform.python_compiler())
- return """
-
- Python %s
%s
-
-
-
- """ % (version, platform.platform(terse=True))
+ def index_columns(self, title, items, css_class):
+ """Create a index section with columns."""
+ section = html._index_section(title, items,
+ css_class="index-columns")
+ template = (''
+ ' {section}'
+ '
'
+ )
+ return template.format(css_class=css_class, section=section)
- def html_index():
- """Module Index page."""
+ def index_lines(self, title, items, css_class):
+ """Create an index section with line."""
+ section = html._index_section(title, items,
+ css_class="index-lines")
+ template = (''
+ ' {section}'
+ '
'
+ )
+ return template.format(css_class=css_class, section=section)
- def bltinlink(name):
- return '%s' % (name, name)
+ html = _HTMLDoc()
- heading = html.heading(
- 'Index of Modules',
- '#ffffff', '#7799ee')
- names = [name for name in sys.builtin_module_names
- if name != '__main__']
- contents = html.multicolumn(names, bltinlink)
- contents = [heading, '' + html.bigsection(
- 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
+ def html_header():
+ values = dict(version=platform.python_version(),
+ build=platform.python_build()[0],
+ compiler=platform.python_compiler(),
+ platform=platform.platform(terse=True),
+ )
+ template = \
+"""
+
+"""
+ return template.format(**values)
- seen = {}
+ def html_modules():
+ """Module Index page."""
+ link_list = ['%s' % (name, name)
+ for name in sys.builtin_module_names
+ if name != '__main__']
+ contents = [html.index_columns('Built-in modules', link_list,
+ css_class='section modules')]
+ shadowed = set()
for dir in sys.path:
- contents.append(html.index(dir, seen))
+ modules = []
+ for importer, name, ispkg in pkgutil.iter_modules([dir]):
+ if name not in shadowed:
+ modules.append((name, ispkg))
+ shadowed.add(name)
+ modules.sort()
+ links = []
+ for name, ispkg in modules:
+ if ispkg:
+ template = (''
+ '{name} (package)')
+ else:
+ template = (''
+ '{name}')
+ link = template.format(name=name)
+ links.append(link)
+ contents.append(html.index_columns(dir,
+ links, css_class='section modules'))
+ content =''.join(contents)
+ template = (''
+ '
Index of Modules
'
+ ' {content}'
+ ''
+ ''
+ )
+ return 'Index of Modules', template.format(content=content)
- contents.append(
- 'pydoc by Ka-Ping Yee'
- '<ping@lfw.org>')
- return 'Index of Modules', ''.join(contents)
-
def html_search(key):
"""Search results page."""
# scan for modules
search_result = []
-
def callback(path, modname, desc):
if modname[-9:] == '.__init__':
modname = modname[:-9] + ' (package)'
- search_result.append((modname, desc and '- ' + desc))
-
+ search_result.append((modname, desc and ' - ' + desc))
with warnings.catch_warnings():
warnings.filterwarnings('ignore') # ignore problems during import
ModuleScanner().run(callback, key)
+ link_list = ['%s%s' % (name, name, desc)
+ for name, desc in search_result]
+ content = html.index_lines('key = %s' % key, link_list,
+ css_class='section modules')
+ template = ('
'
+ '
Search Results
'
+ ' {content}'
+ ''
+ )
+ return 'Search Results', template.format(content=content)
- # format page
- def bltinlink(name):
- return '%s' % (name, name)
-
- results = []
- heading = html.heading(
- 'Search Results',
- '#ffffff', '#7799ee')
- for name, desc in search_result:
- results.append(bltinlink(name) + desc)
- contents = heading + html.bigsection(
- 'key = %s' % key, '#ffffff', '#ee77aa', '
'.join(results))
- return 'Search Results', contents
-
def html_getfile(path):
"""Get and display a source file listing safely."""
- path = path.replace('%20', ' ')
with open(path, 'r') as fp:
lines = html.escape(fp.read())
- body = '%s
' % lines
- heading = html.heading(
- 'File Listing',
- '#ffffff', '#7799ee')
- contents = heading + html.bigsection(
- 'File: %s' % path, '#ffffff', '#ee77aa', body)
- return 'getfile %s' % path, contents
+ title = 'getfile %s' % path.replace('%20', ' ')
+ template = (''
+ '
File Listing
'
+ '
'
+ ' - File: {path}
'
+ ' {lines}
'
+ ' '
+ '
'
+ '
'
+ )
+ return title, template.format(path=path, lines=lines)
def html_topics():
"""Index of topic texts available."""
+ link_list = ['%s' % (name, name)
+ for name in sorted(Helper.topics.keys())]
+ content = html.index_columns('Topics', link_list,
+ css_class="section topics")
+ template = (''
+ '
Index
'
+ ' {content}'
+ ''
+ )
+ return 'Topics', template.format(content=content)
- def bltinlink(name):
- return '%s' % (name, name)
-
- heading = html.heading(
- 'INDEX',
- '#ffffff', '#7799ee')
- names = sorted(Helper.topics.keys())
-
- contents = html.multicolumn(names, bltinlink)
- contents = heading + html.bigsection(
- 'Topics', '#ffffff', '#ee77aa', contents)
- return 'Topics', contents
-
def html_keywords():
"""Index of keywords."""
- heading = html.heading(
- 'INDEX',
- '#ffffff', '#7799ee')
- names = sorted(Helper.keywords.keys())
+ link_list = ['%s' % (name, name)
+ for name in sorted(Helper.keywords.keys())]
+ content = html.index_columns('Keywords', link_list,
+ css_class="section topics")
+ template = (''
+ '
Index
'
+ ' {content}'
+ ''
+ )
+ return 'Keywords', template.format(content=content)
- def bltinlink(name):
- return '%s' % (name, name)
- contents = html.multicolumn(names, bltinlink)
- contents = heading + html.bigsection(
- 'Keywords', '#ffffff', '#ee77aa', contents)
- return 'Keywords', contents
-
def html_topicpage(topic):
"""Topic or keyword help page."""
buf = io.StringIO()
htmlhelp = Helper(buf, buf)
contents, xrefs = htmlhelp._gettopic(topic)
if topic in htmlhelp.keywords:
- title = 'KEYWORD'
+ title = 'Keyword'
else:
- title = 'TOPIC'
- heading = html.heading(
- '%s' % title,
- '#ffffff', '#7799ee')
- contents = '%s
' % contents
- contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
- xrefs = sorted(xrefs.split())
+ title = 'Topic'
+ text = html.markup(contents)
+ link_list = ['%s' % (name, name)
+ for name in sorted(xrefs.split())]
+ xrefs = html.index_columns('Related help Topics', link_list,
+ css_class="section topics")
+ values = dict(
+ title=title,
+ topic=topic,
+ text=text,
+ xrefs=xrefs,
+ )
+ template = (''
+ '
{title}
'
+ '
'
+ ' - {topic}
'
+ ' {text}
'
+ '
'
+ ' {xrefs}'
+ '
'
+ )
+ return '%s %s' % (title, topic), template.format(**values)
- def bltinlink(name):
- return '%s' % (name, name)
+ def html_error(exc, url):
+ values = dict(
+ title = url,
+ exc = repr(exc),
+ err = str(exc),
+ )
+ template = (''
+ '
Error
'
+ '
'
+ ' - {title}
'
+ ' - '
+ '
{exc}'
+ '
{err}'
+ '
'
+ '
'
+ '
'
+ )
+ return "Error - " + url, template.format(**values)
- xrefs = html.multicolumn(xrefs, bltinlink)
- xrefs = html.section('Related help topics: ',
- '#ffffff', '#ee77aa', xrefs)
- return ('%s %s' % (title, topic),
- ''.join((heading, contents, xrefs)))
-
- def html_error(url):
- heading = html.heading(
- 'Error',
- '#ffffff', '#ee0000')
- return heading + url
-
def get_html_page(url):
"""Generate an HTML page for url."""
- if url.endswith('.html'):
- url = url[:-5]
- if url.startswith('/'):
- url = url[1:]
- if url.startswith("get?key="):
- url = url[8:]
- title = url
- contents = ''
- if url in ("", ".", "index"):
- title, contents = html_index()
- elif url == "topics":
- title, contents = html_topics()
- elif url == "keywords":
- title, contents = html_keywords()
- elif url.startswith("search?key="):
- title, contents = html_search(url[11:])
- elif url.startswith("getfile?key="):
- url = url[12:]
- try:
- title, contents = html_getfile(url)
- except IOError:
- contents = html_error('could not read file %r' % url)
- title = 'Read Error'
- else:
- obj = None
- try:
+ try:
+ if url.endswith('.html'):
+ url = url[:-5]
+ if url.startswith('/'):
+ url = url[1:]
+ if url.startswith("get?key="):
+ url = url[8:]
+ if url in ("", ".", "index"):
+ title, content = html_modules()
+ elif url == "topics":
+ title, content = html_topics()
+ elif url == "keywords":
+ title, content = html_keywords()
+ elif url.startswith("search?key="):
+ title, content = html_search(url[11:])
+ elif url.startswith("getfile?key="):
+ path = url[12:]
+ title, content = html_getfile(path)
+ elif url in Helper.keywords or url in Helper.topics:
+ title, content = html_topicpage(url)
+ else:
obj = locate(url, forceload=1)
- except ErrorDuringImport as value:
- contents = html.escape(str(value))
- if obj:
+ if obj is None and url != "None":
+ raise ValueError('could not find "%s"' % url)
title = describe(obj)
- contents = html.document(obj, url)
- elif url in Helper.keywords or url in Helper.topics:
- title, contents = html_topicpage(url)
- else:
- contents = html_error(
- 'no Python documentation found for %r' % url)
- title = 'Error'
- return html.page(title, html_navbar() + contents)
+ content = ('%s
' %
+ html.document(obj, url))
+ except Exception as exc:
+ title, content = html_error(exc, url)
+ return html.page(title, content)
if url.startswith('/'):
url = url[1:]
if content_type == 'text/css':
path_here = os.path.dirname(os.path.realpath(__file__))
- try:
- with open(os.path.join(path_here, url)) as fp:
- return ''.join(fp.readlines())
- except IOError:
- return 'Error: can not open css file %r' % url
+ with open(os.path.join(path_here, url)) as fp:
+ return ''.join(fp.readlines())
elif content_type == 'text/html':
return get_html_page(url)
- return 'Error: unknown content type %r' % content_type
+ raise ValueError('unknown content type: (%r, %r)' % (content_type, url))
def browse(port=0, *, open_browser=True):
@@ -2720,6 +2785,8 @@
print('Server ready at', serverthread.url)
print(server_help_msg)
while serverthread.serving:
+ if serverthread.error:
+ print(serverthread.error)
cmd = input('server> ')
cmd = cmd.lower()
if cmd == 'q':
Index: Lib/test/test_pydoc.py
===================================================================
--- Lib/test/test_pydoc.py (revision 87586)
+++ Lib/test/test_pydoc.py (working copy)
@@ -419,30 +419,27 @@
"""Tests for pydoc._url_handler"""
def test_content_type_err(self):
- err = 'Error: unknown content type '
f = pydoc._url_handler
- result = f("", "")
- self.assertEqual(result, err + "''")
- result = f("", "foobar")
- self.assertEqual(result, err + "'foobar'")
+ self.assertRaises(ValueError, f, "", "")
+ self.assertRaises(ValueError, f, "", "foobar")
def test_url_requests(self):
# Test for the correct title in the html pages returned.
# This tests the different parts of the URL handler without
# getting too picky about the exact html.
requests = [
- ("", "Python: Index of Modules"),
- ("get?key=", "Python: Index of Modules"),
- ("index", "Python: Index of Modules"),
- ("topics", "Python: Topics"),
- ("keywords", "Python: Keywords"),
- ("pydoc", "Python: module pydoc"),
- ("get?key=pydoc", "Python: module pydoc"),
- ("search?key=pydoc", "Python: Search Results"),
- ("def", "Python: KEYWORD def"),
- ("STRINGS", "Python: TOPIC STRINGS"),
- ("foobar", "Python: Error"),
- ("getfile?key=foobar", "Python: Read Error"),
+ ("", "PyDoc: Index of Modules"),
+ ("get?key=", "PyDoc: Index of Modules"),
+ ("index", "PyDoc: Index of Modules"),
+ ("topics", "PyDoc: Topics"),
+ ("keywords", "PyDoc: Keywords"),
+ ("pydoc", "PyDoc: module pydoc"),
+ ("get?key=pydoc", "PyDoc: module pydoc"),
+ ("search?key=pydoc", "PyDoc: Search Results"),
+ ("def", "PyDoc: Keyword def"),
+ ("STRINGS", "PyDoc: Topic STRINGS"),
+ ("foobar", "PyDoc: Error - foobar"),
+ ("getfile?key=foobar", "PyDoc: Error - getfile?key=foobar"),
]
for url, title in requests:
@@ -451,7 +448,7 @@
self.assertEqual(result, title)
path = string.__file__
- title = "Python: getfile " + path
+ title = "PyDoc: getfile " + path
url = "getfile?key=" + path
text = pydoc._url_handler(url, "text/html")
result = get_html_title(text)